package com.zgjkhis.modules.charges.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zgjkhis.common.service.impl.BaseServiceImpl;
import com.zgjkhis.exception.ServiceException;
import com.zgjkhis.modules.charges.domain.Logistics;
import com.zgjkhis.modules.charges.domain.PrescriptionOrder;
import com.zgjkhis.modules.charges.service.LogisticsRouteService;
import com.zgjkhis.modules.charges.service.LogisticsService;
import com.zgjkhis.modules.charges.service.PrescriptionService;
import com.zgjkhis.modules.charges.service.dto.LogisticsRouteDto;
import com.zgjkhis.modules.charges.service.dto.LogisticsStatusDto;
import com.zgjkhis.modules.charges.service.mapper.LogisticsMapper;
import com.zgjkhis.modules.security.security.LoginUserUtil;
import com.zgjkhis.modules.system.domain.Store;
import com.zgjkhis.modules.system.service.StoreService;
import com.zgjkhis.modules.util.CharUtil;
import com.zgjkhis.modules.util.LogisticsUtil;
import com.zgjkhis.utils.DateUtils;
import com.zgjkhis.utils.RandomUtils;
import com.zgjkhis.utils.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author yxl
 * @Description 物流service实现类
 * @Date 2021/7/19 11:17
 **/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class LogisticsServiceImpl extends BaseServiceImpl<LogisticsMapper, Logistics> implements LogisticsService {


    private final static Logger logger = LoggerFactory.getLogger(LogisticsServiceImpl.class);
//    @Value("${shunFen.hospitalCode}")
//    private String hospitalCode;
//    @Value("${shunFen.srcCompany}")
//    private String srcCompany;
//    @Value("${shunFen.monthlyCard}")
//    private String monthlyCard;
//    @Value("${shunFen.secretKey}")
//    private String secretKey;
    private final String baseUrl = "";
    @Resource
    private LogisticsRouteService routeService;
    @Resource
    private PrescriptionService prescriptionService;
    @Resource
    private StoreService storeService;

    @Override
    public void addOrder(PrescriptionOrder order, Logistics logistics, String[] orderNOs, List<String> apiOrderNos) {
        List<Logistics> list = new ArrayList<>();
        String orderCode = DateUtils.dateTimeNow() + RandomUtils.getRandomNumbers(6);
        logistics.setBspOrderNo(orderCode);
        if (logistics.getPackagesNo() == null || logistics.getPackagesNo().intValue() == 0) {
            logistics.setPackagesNo(1);
        }
        Store store = storeService.getFromCatchById(order.getPharmacyId());
        JSONObject shunFenJson = this.getParamList(store, order, logistics);
        String appId = store.getAppId();
        String version = "1.0.0";
        String timestamp = System.currentTimeMillis() + "";
        String appIdSecret = store.getAppIdSecret();
        String sign = SecureUtil.md5(appId + version + timestamp + appIdSecret);
        String urlParam = "appid=" + appId + "&version=" + version + "&timestamp=" + timestamp + "&sign=" + sign;
        String result = HttpUtil.post(baseUrl + "addOrder?" + urlParam, shunFenJson.toJSONString());
        if (CharUtil.isEmpty(result)) {
            throw new ServiceException("顺丰接口异常");
        }
        logger.info("{}--物流接口返回报文：{}", order.getOrderNo(), result);
        JSONObject jsonobject = JSONObject.parseObject(result);
        if (!"200".equals(jsonobject.getString("code"))) {
            String message = jsonobject.getString("msg");
            logger.info(String.format("下单失败:%s", message));
            throw new ServiceException(String.format("下单失败:%s", message));
        }
        JSONObject json = jsonobject.getJSONObject("data");
        String code = json.getString("code");
        if (!"200".equals(code)) {
            String message = json.getString("msg");
            logger.info(String.format("下单失败:%s", message));
            throw new ServiceException(String.format("下单失败:%s", message));
        }
        logistics.setMailNo(json.getString("expressNo"));
        logistics.setStatus(2);
        list.add(logistics);
        for (int i = 1; i < orderNOs.length; i++) {
            Logistics temp = new Logistics();
            BeanUtil.copyProperties(logistics, temp);
            temp.setOrderNo(orderNOs[i]);
            list.add(temp);
        }
        this.saveBatch(list);
        LogisticsUtil.sendLogistic(apiOrderNos, logistics, "2", shunFenJson, "1");
    }

    @Override
    public List<Logistics> queryOrder(String orderNo) {
        QueryWrapper<Logistics> wrapper = new QueryWrapper();
        wrapper.lambda().eq(Logistics::getOrderNo, orderNo);
        wrapper.lambda().orderByDesc(Logistics::getCreateTime);
        return super.list(wrapper);
    }

    @Override
    public List<LogisticsRouteDto> queryLogistics(String orderNo) {
        QueryWrapper<Logistics> wrapper = new QueryWrapper();
        List<LogisticsRouteDto> result = new ArrayList<>();
        wrapper.eq("order_no", orderNo);
        List<Logistics> logistics = super.list(wrapper);

        if (!ArrayUtil.isEmpty(logistics)) {
            logistics.forEach(item -> {
                result.add(new LogisticsRouteDto(item, this.routeService.queryByNo(item.getBspOrderNo())));
            });
        }

        return result;
    }

    @Override
    public List<Logistics> queryNoComplete() {
        QueryWrapper<Logistics> wrapper = new QueryWrapper();
        wrapper.lambda().eq(Logistics::getStatus, 2);
        wrapper.lambda().isNotNull(Logistics::getMailNo);

        Date date = new Date();//获取当前时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -15);

        wrapper.lambda().ge(Logistics::getCreateTime, calendar.getTime());

        return super.list(wrapper);
    }

    @Override
    public List<LogisticsStatusDto> requestStatus(String orderNo) {

        PrescriptionOrder order = prescriptionService.getOne(Wrappers.<PrescriptionOrder>query().lambda().eq(PrescriptionOrder::getOrderNo, orderNo));
        // 顺丰订单参数
        Store store = storeService.getFromCatchById(order.getPharmacyId());

        QueryWrapper<Logistics> wrapper = new QueryWrapper();
        List<LogisticsStatusDto> result = new ArrayList<>();
        wrapper.eq("order_no", orderNo);
        List<Logistics> logistics = super.list(wrapper);
        if (!ArrayUtil.isEmpty(logistics)) {
            logistics.forEach(item -> {
                result.add(new LogisticsStatusDto(item, this.requestOrderRoute(store, item)));
            });
        }
        return result;
    }

    @Override
    public ResponseEntity<Object> cancelThirdOrder(String logisticsId) {
        logger.info("进入时间：" + DateUtils.dateTimeNow());
        Logistics logistics = this.getOne(Wrappers.<Logistics>query().lambda().eq(Logistics::getId, logisticsId));
        if (CharUtil.isEmpty(logistics) || logistics.getStatus() == 4) {
            throw new ServiceException("物流已拦截");
        }
        String url = this.baseUrl + "cancelThirdOrder";
        PrescriptionOrder order = prescriptionService.getOne(Wrappers.<PrescriptionOrder>query().lambda().eq(PrescriptionOrder::getOrderNo, logistics.getOrderNo()));
        // 顺丰订单参数
        Store store = storeService.getFromCatchById(order.getPharmacyId());

        Map param = new HashMap<>();
        param.put("orderNo", logistics.getBspOrderNo());
        param.put("channelId", store.getChannelId());
        param.put("offline", logistics.getOffline());
        param.put("expressChannel", logistics.getExpressChannel());
        String appId = store.getAppId();
        String version = "1.0.0";
        String timestamp = System.currentTimeMillis() + "";
        String appIdSecret = store.getAppIdSecret();
        String sign = SecureUtil.md5(appId + version + timestamp + appIdSecret);
        String urlParam = "appid=" + appId + "&version=" + version + "&timestamp=" + timestamp + "&sign=" + sign;
        logger.info("进入时间2：" + DateUtils.dateTimeNow());
        String result = HttpUtil.get(url + "?" + urlParam, param);
        logger.info("进入时间3：" + DateUtils.dateTimeNow());
        JSONObject json = JSONObject.parseObject(result);
        if (!"200".equals(json.getString("code"))) {
            String message = json.getString("msg");
            logger.info(String.format("取消物流失败:%s", message));
            throw new ServiceException(String.format("取消物流失败:%s", message));
        }
        String orderNo = json.getString("data");
        this.update(Wrappers.<Logistics>update().lambda().set(Logistics::getStatus, 4)
                .set(Logistics::getCancelOperateUserId, SecurityUtils.getUserId())
                .set(Logistics::getCancelOperateUser, LoginUserUtil.getNickName())
                .set(Logistics::getCancelOperateTime, new Date())
                .eq(Logistics::getBspOrderNo, logistics.getBspOrderNo()));
        prescriptionService.updateOrderCondition(logistics.getBspOrderNo());
        List<PrescriptionOrder> list = prescriptionService.queryListByBspOrderNo(logistics.getBspOrderNo());
        //回调 取消物流
        logger.info("进入时间4：" + DateUtils.dateTimeNow());
        LogisticsUtil.sendLogistic(list.stream().map(r -> r.getApiOrderNo()).collect(Collectors.toList()), logistics, "4", null, "2");
        logger.info("进入时间5：" + DateUtils.dateTimeNow());
        return new ResponseEntity(json.getString("msg"), HttpStatus.OK);
    }

    @Override
    public JSONArray queryLogisticsFromInterface(String logisticsId) {
        Logistics logistics = this.getById(logisticsId);
        if (CharUtil.isEmpty(logistics)) {
            throw new ServiceException("查无此物流");
        }
        Store store = storeService.getFromCatchById(logistics.getPharmacyId());
        String result = LogisticsUtil.listOrderRoute(logistics.getMailNo(), store.getAppId(), store.getAppIdSecret(), baseUrl);
        JSONObject temp = JSONObject.parseObject(result);
        if (!"200".equals(temp.getString("code"))) {
            String message = temp.getString("msg");
            logger.info(String.format("物流信息查询失败:%s", message));
            throw new ServiceException(String.format("物流信息查询失败:%s", message));
        }
        JSONObject jsonObject = temp.getJSONObject("data");
        JSONArray array = jsonObject.getJSONArray("route");
        return array;
    }

    private JSONObject getParamList(Store store, PrescriptionOrder order, Logistics logistics) {
        JSONObject json = new JSONObject();

        // 业务订单号(医院自定义、唯一不重复)
        json.put("orderNo", logistics.getBspOrderNo());
        // 1为寄付，2为到付，寄付月结的payMethod传1,再传月结卡号即可,3为寄付转第三方
        json.put("payMethod", logistics.getPayMethod().toString());
        // 使用的顺丰产品类型 标快 2为顺丰标快（陆运），208为特惠专配，229为精温专递，232为精温专递（样本），233为精温专递（样本陆），采用其他产品请先咨询业务方)
        json.put("expressType", logistics.getExpressType().toString());
        // 寄件公司
        json.put("srcCompany", store.getStoreName());
        // 寄件人姓名
        json.put("srcName", logistics.getSrcName());
        // 寄件人电话（电话）
        json.put("srcPhone", logistics.getSrcPhone());
        // 寄件人省份
        json.put("srcProvince", logistics.getSrcProvince());
        // 寄件人城市
        json.put("srcCity", logistics.getSrcCity());
        // 寄件人镇/区
        json.put("srcDistrict", logistics.getSrcDistrict());
        // 寄件人详细地址
        json.put("srcAddress", logistics.getSrcAddress());
        // 收件人姓名
        json.put("destName", logistics.getDestName());

        // 收件人省份
        json.put("destProvince", logistics.getDestProvince());
        // 收件人城市
        json.put("destCity", logistics.getDestCity());
        // 收件人镇区
        json.put("destDistrict", logistics.getDestDistrict());
        // 收件人详细地址
        json.put("destAddress", logistics.getDestAddress());
        // 收件人电话（手机）
        json.put("destPhone", logistics.getDestPhone());
        // 包裹重量
        json.put("parcelWeighs", logistics.getParcelWeighs());
        // 件数，不填默认1
//        json.put("packagesNo", logistics.getPackagesNo());
        json.put("packagesNo", 1);
        // 寄托物名称
        json.put("depositumInfo", logistics.getConsignment());
        // 备注
        json.put("remark", logistics.getRemark());
        // 产品code
        json.put("productCode", logistics.getProductCode());
        json.put("channelId", store.getChannelId());
        json.put("patientName", order.getPatientName());
        json.put("takeMedicineIdentityName", "订单号");
        json.put("takeMedicineIdentityValue", order.getApiOrderNo());
        json.put("offline", logistics.getOffline());
        json.put("expressChannel", logistics.getExpressChannel());
        if (logistics.getOffline() == 1) {
            if (CharUtil.isEmpty(logistics.getMailNo())) {
                throw new ServiceException("线下发货,快递单号不能为空");
            } else if (logistics.getMailNo().length() <= 2) {
                throw new ServiceException("线下发货,快递单号错误");
            }
            json.put("mailNo", logistics.getMailNo());
        }

//        // 声明价值（单位：分）
//        json.put("statementValue", logistics.getStatementValue());
//
//        // 月结卡号 如果是月结，必须要填
//        if(logistics.getPayMethod().intValue() == 1 && !CharUtil.isEmpty(this.monthlyCard)) {
//            json.put("monthlyCard", this.monthlyCard);
//        }
//        // 医院代码
//        json.put("hospitalCode", this.hospitalCode);

        return json;
    }

    private JSONObject requestOrderRoute(Store store, Logistics logistics) {
        String result = LogisticsUtil.listOrderRoute(logistics.getMailNo(), store.getAppId(), store.getAppIdSecret(), baseUrl);
        if (result == null) {
            throw new ServiceException("系统错误");
        }
        JSONObject temp = JSONObject.parseObject(result);
        if (!"200".equals(temp.getString("code"))) {
            String message = temp.getString("msg");
            logger.info(String.format("物流信息查询失败:%s", message));
            throw new ServiceException(String.format("物流信息查询失败:%s", message));
        }
        JSONObject jsonObject = temp.getJSONObject("data");
        String message = jsonObject.getString("message");
        if (!CharUtil.isEmpty(message)) {
            throw new ServiceException(String.format("请求失败：%s", message));
        }
        JSONObject json = jsonObject.getJSONObject("result");
        return json;
    }

}
